//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   AngularMesh.hh
 * \author Jeremy Roberts
 * \date   06/19/2011
 * \brief  AngularMesh class definition.
 * \note   Copyright (C) 2011 Jeremy Roberts. Adapted from Denovo.
 */
//---------------------------------------------------------------------------//
// $Rev:: 133                                           $:Rev of last commit
// $Author:: j.alyn.roberts@gmail.com                   $:Author of last commit
// $Date:: 2011-09-08 19:31:48 +0000 (Thu, 08 Sep 2011) $:Date of last commit
//---------------------------------------------------------------------------//

#ifndef ANGULARMESH_HH
#define ANGULARMESH_HH

#include <vector>

#include "angle/Octant.hh"
#include "tran/Traits.hh"
#include "../utilities/DBC.hh"
#include "../utilities/SP.hh"
#include "../utilities/Constants.hh"

namespace slabtran
{

//===========================================================================//
/*!
 * \class AngularMesh
 * \brief Holds all of the octant/angular information for a discrete ordinates
 * solve.
 *
 * The AngularMesh is a class that describes the angular discretization of
 * the problem.  In this case, \f$ S_N\f$ is a finite-element collocation
 * method that generates solutions at discrete angles.  The angles are
 * arranged by octants so that \f$ S_N\f$ schemes that are aligned along axes
 * (orthogonal-mesh methods) can take advantage of the octants.  Unstructured
 * mesh schemes will generally ignore the octants; although, this causes no
 * extra hardship.
 *
 * The AngularMesh class holds all 8 octants for the mesh.  The actual angles
 * and quadrature weights are defined in the Octant class.  Currently, the
 * octants store angular quadratures based on the Level-Symmetric quadrature
 * set.  Others may be added in the future.  See Octant for more details.
 *
 * \sa Octant.
 *
 * \todo We may want an interface for accessing an \f$ \Omega \f$ directly.
 */
/*! 
 * \example test/testAngularMesh.cc
 *
 * Test of AngularMesh.
 */
//===========================================================================//

template <class D>
class AngularMesh
{

public:

  //\{
  //! Typedefs.
  typedef util::SP<AngularMesh<D> >             SP_angularmesh;
  typedef unsigned int                          size_type;
  typedef util::SP<Octant<D> >                  SP_octant;
  typedef std::vector<SP_octant>                Vec_Octants;
  typedef typename Vec_Octants::iterator        iterator;
  typedef typename Vec_Octants::const_iterator  const_iterator;
  //\}

  //! Octant enumerators.                // needs for multi-d
  enum Octant_Numbers
  {
    PPP = 0,
    MPP = 1, // 1-d . 2-d . 3-d .
    PMP = 2,
    MMP = 3, //           .     .
    PPM = 4,
    MPM = 5, //                 .
    PMM = 6,
    MMM = 7, //                 .
    NUM_OCTANTS = 8
  };

public:

  /*!
   *  \brief Constructor.
   *  \param    order       Quadrature order.
   *  \param    quad_type   Quadrature type.
   *  \param    do_adjoint  Doing adjoint or not.
   */
  explicit AngularMesh(const size_type order,
                       int quad_type,
                       bool do_adjoint = false);

  /// \name Accessors
  //\{

  /// Get an octant. Inline.
  const Octant<D>& octant(int octant_number) const;

  /// Query to see if we are running with adjoint octants.
  bool adjoint() const
  {
    return d_octants[0]->adjoint();
  }

  /// Number of octants.
  size_type number_octants()
  {
    return d_number_octants;
  }

  /// Number of angles per octant.
  size_type number_angles_octant()
  {
    return d_octants[0]->number_angles();
  }

  /// Total number of angles in this angular mesh.
  size_type number_angles() const
  {
    return d_octants[0]->number_angles() * d_number_octants;
  }

  /// Cardinal angular index.
  size_type index(int o, int n)
  {
    Require(o >= 0 && o < d_number_octants);
    Require(n >= 0 && n < d_octants[0]->number_angles());
    return o * d_octants[0]->number_angles() + n;
  }

  /// \f$ S_N\f$ order.
  size_type sn_order() const
  {
    return d_order;
  }

  /// Mutable iterator to beginning octant.
  iterator begin()
  {
    return d_octants.begin();
  }

  /// Const iterator to beginning octant.
  const_iterator begin() const
  {
    return d_octants.begin();
  }

  /// Mutable iterator to (one-past) last octant.
  iterator end()
  {
    return d_octants.end();
  }

  /// Const iterator to (one-past) last octant.
  const_iterator end() const
  {
    return d_octants.end();
  }

  //\}

private:
  // >>> DATA

  // Sn order.
  size_type d_order;

  // Vector of all (2 or 4 or 8) octants.
  Vec_Octants d_octants;

  // Number of octants = 2**N
  int d_number_octants;

};

} // end namespace slabtran

//---------------------------------------------------------------------------//
// INLINE FUNCTIONS
//---------------------------------------------------------------------------//

#include "angle/AngularMesh.i.hh"

#endif // ANGULARMESH_HH
//---------------------------------------------------------------------------//
//              end of AngularMesh.hh
//---------------------------------------------------------------------------//
